#!/usr/bin/python
import pickle
import re
import sys
from geopy import geocoders  
import urllib
import xml.dom.minidom
import time


class Geocoder:
    KEY = 'GOOGLE_API_KEY'
    MAX_QPS = 2.0
    def __init__(self, cacheobj = None):
        self.__coder = geocoders.Google(self.KEY)
        self._last_geocode = 0
        if cacheobj is not None:
          self._cacheobj = cacheobj
        else:
          self._cacheobj = {}

    def getCache(self):
      return self._cacheobj


    def GeocodePoint(self, loc):

        if not self._cacheobj.has_key(loc):

          interval = (time.time() - self._last_geocode)
          if interval < (1.0 / self.MAX_QPS):
            time.sleep((1/self.MAX_QPS) - interval)
          self._last_geocode = time.time()

          rval = self.__coder.geocode(loc)
          self._cacheobj[loc] = rval

        _, (lat,lon) = self._cacheobj[loc]
        return (lon,lat)

    def GeocodePointAsString(self, loc):
        return '%s,%s' % self.GeocodePoint(loc)

def createPlacemark(coder, kmlDoc, pointtpl):
  # This creates a  element for a row of data.
  # A row is a dict.
  placemarkElement = kmlDoc.createElement('Placemark')
  descriptionElement = kmlDoc.createElement('description')
  placemarkElement.appendChild(descriptionElement)
#  extElement = kmlDoc.createElement('ExtendedData')
#  placemarkElement.appendChild(extElement)
  
#  dataElement = kmlDoc.createElement('Data')
#  dataElement.setAttribute('name', 'description')
#  valueElement = kmlDoc.createElement('value')
#  dataElement.appendChild(valueElement)
  valueText = kmlDoc.createTextNode(pointtpl[1])
#  valueElement.appendChild(valueText)
  descriptionElement.appendChild(valueText)
#  extElement.appendChild(dataElement)
  
  pointElement = kmlDoc.createElement('Point')
  placemarkElement.appendChild(pointElement)
  coordinates = coder.GeocodePointAsString(pointtpl[0])
  coorElement = kmlDoc.createElement('coordinates')
  coorElement.appendChild(kmlDoc.createTextNode(coordinates))
  pointElement.appendChild(coorElement)
  return placemarkElement

def MakeKML(allpoints, outfile=None, cachefile='./geocache.bin'):
  """ returns a kml document to a new xml file.
  allpoints: map of location to description
  outfile: name of file. it's destroyed.
  """

    # This function creates an XML document and adds the necessary
    # KML elements.
    # pass
  cacheobj = None
  if cachefile is not None:
    try:
      f = open(cachefile, 'r')
      cacheobj = pickle.load(f)
      f.close()
      print 'cache has %d elements' % len(cacheobj)
    except pickle.PickleError, e:
      print e
    except IOError, e1:
      print e1
      

  g = Geocoder(cacheobj=cacheobj)
  kmlDoc = xml.dom.minidom.Document()
  
  kmlElement = kmlDoc.createElementNS('http://earth.google.com/kml/2.2', 'kml')
  kmlElement.setAttribute('xmlns','http://earth.google.com/kml/2.2')
  kmlElement = kmlDoc.appendChild(kmlElement)
  documentElement = kmlDoc.createElement('Document')
  documentElement = kmlElement.appendChild(documentElement)

  for pointtpl in allpoints.items():
      try:
          placemarkElement = createPlacemark(g, kmlDoc, pointtpl)#, order)
          documentElement.appendChild(placemarkElement)
      except ValueError, e:
          print >>sys.stderr, "ERROR for %s "  % str(pointtpl)
          print >> sys.stderr, e

  rval = kmlDoc.toprettyxml('  ', newl = '\n',)# encoding = 'utf-8'))

  if cachefile is not None:
    print 'cache has %d elements' % len(g.getCache())
    #TODO use tmp file
    f  = open(cachefile, 'w')
    pickle.dump(g.getCache(), f)

  if outfile is not None:
    kmlFile = open(outfile, 'w')
    kmlFile.write(rval)
    kmlFile.close()

  return rval

if __name__ == '__main__': 
  allpoints = {}
  x = 0
  for i in sys.argv[1:]:
    allpoints[i] = 'location %d' % x
    x += 1
    
  print allpoints
  print MakeKML(allpoints)
